﻿using Furion.FriendlyException;
using Gear.NoSql.Core;
using Gear.NoSql.Core.Mongo;
using Gear.NoSql.Core.Tool;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Gear.Application.Service.File
{
    /// <summary>
    /// 文件帮助类
    /// </summary>
    
    public static class FileHelper
    {
        #region ==Mongo文件存储==

        /// <summary>
        /// 初始化GridFSBucket
        /// </summary>
        private static GridFSBucket bucket = MongoClientSetting.bucket(new GridFSBucketOptions
        {
            BucketName = MongoClientSetting.Bucket,//设置根节点名
            //ChunkSizeBytes = 1024 * 1024,   //设置块的大小为1M
            WriteConcern = WriteConcern.WMajority,     //写入确认级别为majority
            ReadPreference = ReadPreference.Secondary  //优先从从节点读取
        });

        /// <summary>
        /// 上传返回id
        /// </summary>
        /// <param name="metaflies">配置项参数</param>
        /// <returns></returns>
        public static List<mognoinfo> Upload(List<MetaFlies> metaflies)
        {
            //List<FileIDs> fileids = new List<FileIDs>();
            List<mognoinfo> idAry = new List<mognoinfo>();
            //上传的配置项，可以添加文件元数据
            var ListOptions = new List<GridFSUploadOptions>();

            //通过stream形式上传文件
            ObjectId fileId;

            try
            {
                metaflies.ForEach(f =>
                {
                    var i = metaflies.IndexOf(f);
                    var options = new GridFSUploadOptions
                    {
                        Metadata = NoSqlTool.StrToBD(NoSqlTool.ObjectToJson(metaflies[i].metaflie)),
                    };
                    fileId = bucket.UploadFromStream(filename: NoSqlTool.EntityID, source: f.file, options: options);
                    
                    idAry.Add(new mognoinfo { fileid = fileId.ToString(), type = metaflies[i].metaflie.subjoin == null ? null : metaflies[i].metaflie.subjoin.ToString() });
                });
            }
            catch(Exception e)
            {
                throw Oops.Oh(e.Message);
            }

            //生成缩略图并上传
            //idAry.ForEach(id => {
            //    //生成缩略图
            //    var thumbnail = Tool.ByteToStream(Thumbnail(id));
            //    fileId = bucket.UploadFromStream(filename: Tool.EntityID, source: thumbnail);
            //    fileids.Add(new FileIDs { mainid = id, subid = fileId.ToString() });
            //});
            return idAry;

        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="fileId">文件ID</param>
        /// <returns></returns>
        public static bool Delete(string fileId)
        {
            try
            {
                var objid = new ObjectId(fileId);
                bucket.Delete(id: objid);
                AttachmentDelete(fileId);// 文件记录表数据删除

            }
            catch (Exception)
            {
                throw new Exception("未找到文件！");
            }
            return true;
        }
        /// <summary>
        /// 异步读取byte[]
        /// </summary>
        /// <param name="objid"></param>
        /// <returns></returns>
        public static async Task<byte[]> ReadAsync(string objid)
        {
            var bs = bucket.DownloadAsBytesAsync(new ObjectId(objid));
            bs.Wait();
            return await bs;
        }
        /// <summary>
        /// 根据objid读取byte[]
        /// </summary>
        /// <param name="objid"></param>
        /// <returns></returns>
        public static byte[] Read(string objid) => bucket.DownloadAsBytes(new ObjectId(objid));
        /// <summary>
        /// 根据objid读取stream
        /// </summary>
        /// <param name="objid"></param>
        /// <param name="destination"></param>
        public static string ReadStream(string objid, Stream destination)
        {
            bucket.DownloadToStream(new ObjectId(objid), destination);
            return GetFileType(objid);
        }
        /// <summary>
        /// 根据objid读取stream
        /// </summary>
        /// <param name="objid"></param>
        /// <returns></returns>
        public static streamtype ReadStream_Thumb(string objid)
        {
            return new streamtype { stream = Thumbnail(objid), type = GetFileType(objid) };
        }
        public static string GetFileType(string objid) => NoSqlTool.DeserializeJsonToObject<MetaFlie>(Find(objid)?[0].Metadata.ToString()).filetype;
        public static string GetFileSuffix(string objid) => NoSqlTool.DeserializeJsonToObject<MetaFlie>(Find(objid)?[0].Metadata.ToString()).suffix;
        public static string GetFileAutonym(string objid) => NoSqlTool.DeserializeJsonToObject<MetaFlie>(Find(objid)?[0].Metadata.ToString()).autonym;
        
        /// <summary>
        /// 获取文件类型
        /// </summary>
        /// <param name="objid"></param>
        /// <returns></returns>
        public static string GetFileKind(string objid)
        {
            var type = GetFileType(objid);
            string kind = string.Empty;
            //using (var conn = DBHelper.GetConnection())
            //{
            //    kind = conn.Query<string>(@"select (select codevalue from PZ_CONFIGURATION where id=ta.parentid) codevalue
            //                              from (select t.parentid, t.codevalue
            //                                      from PZ_CONFIGURATION t
            //                                     start with t.parentid = 9000300
            //                                    connect by PRIOR t.id = t.parentid) ta
            //                             where ta.codevalue = :type", new { type = type }).SingleOrDefault();
            //    kind ??= "other";
            //}
            return kind;
        }
        public static async Task<GridFSFileInfo> GetFileById(string objid)
        {
            var filter = Builders<GridFSFileInfo>.Filter.Eq("_id", new ObjectId(objid));
            return await bucket.Find(filter).FirstOrDefaultAsync();
        }
        public static async Task<GridFSDownloadStream> DownloadFileStream(string objid)
        {
            return await bucket.OpenDownloadStreamAsync(new ObjectId(objid));
        }
        /// <summary>
        /// 压缩
        /// </summary>
        /// <param name="objid"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        private static byte[] Reduce(string objid, int width = 0, int height = 0)
        {
            //获取源图
            var socbytes = Read(objid);
            if (socbytes.Length < MongoClientSetting.threshold)
                return socbytes;
            var bms = NoSqlTool.ByteToImg(socbytes);
            //要生成的缩略图的宽度
            int thumbWidth = width == 0 ? bms.Width / MongoClientSetting.multiple : width;
            //要生成的缩略图的高度
            int thumbHeight = height == 0 ? bms.Height / MongoClientSetting.multiple : height;
            //创建画布(默认缩小倍率)
            Bitmap bmp = new Bitmap(thumbWidth, thumbHeight);
            //从Bitmap创建一个System.Drawing.Graphics对象，用来绘制高质量的缩小图。
            System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(bmp);
            //设置 System.Drawing.Graphics对象的SmoothingMode属性为HighQuality
            gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //下面这个也设成高质量
            gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            //下面这个设成High
            gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            //把原始图像绘制成上面所设置宽高的缩小图
            System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
            gr.DrawImage(bms, rectDestination, 0, 0, bms.Width, bms.Height, GraphicsUnit.Pixel);
            //保存byte[]
            var bytes = NoSqlTool.ImgToByte(bmp);
            bmp.Dispose();
            return bytes;
        }
        /// <summary>
        /// 缩略图
        /// </summary>
        /// <param name="objid"></param>
        /// <returns></returns>
        public static Stream Thumbnail(string objid)
        {
            //获取源图
            var socbytes = Read(objid);
            var bms = NoSqlTool.ByteToImg(socbytes);
            //要生成的缩略图的宽度
            int thumbWidth = 140;
            //要生成的缩略图的高度
            int thumbHeight = 140;
            //创建画布(默认缩小倍率)
            Bitmap bmp = new Bitmap(thumbWidth, thumbHeight);
            //从Bitmap创建一个System.Drawing.Graphics对象，用来绘制高质量的缩小图。
            System.Drawing.Graphics gr = System.Drawing.Graphics.FromImage(bmp);
            //设置 System.Drawing.Graphics对象的SmoothingMode属性为HighQuality
            gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //下面这个也设成高质量
            gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            //下面这个设成High
            gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            //把原始图像绘制成上面所设置宽高的缩小图
            System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(0, 0, thumbWidth, thumbHeight);
            gr.DrawImage(bms, rectDestination, 0, 0, bms.Width, bms.Height, GraphicsUnit.Pixel);
            //保存byte[]
            var bytes = NoSqlTool.ImgToByte(bmp);
            bmp.Dispose();
            return NoSqlTool.ByteToStream(bytes);
        }
        /// <summary>
        /// 获取GridFSFileInfo
        /// </summary>
        /// <param name="fileid"></param>
        /// <returns></returns>
        public static List<GridFSFileInfo> Find(string fileid) => bucket.Find(new { _id = new ObjectId(fileid) }.ToBsonDocument()).ToList().Count == 0 ? null : bucket.Find(new { _id = new ObjectId(fileid) }.ToBsonDocument()).ToList();

        /// <summary>
        /// 附件表记录
        /// </summary>
        /// <param name="files"></param>
        /// <param name="pkvalue"></param>
        /// <param name="tablename"></param>
        /// <returns></returns>
        public static List<mognoinfo> AttachmentRecord(List<mognoinfo> files,string pkvalue,string tablename)
        {
            try
            {
                //using (var conn = DBHelper.GetConnection())
                //{
                //    string key = string.Empty;
                //    if (tablename == "res_psn_user")
                //        key = "userid";
                //    else if (tablename == "res_psn_organization")
                //        key = "orgid";
                //    else
                //        key = "id";
                //    var count = SqlMapper.Query<int>(conn, @"select count(1) from " + tablename + " where 1=1 and " + key + "=:pkvalue",
                //            new { pkvalue = pkvalue }).FirstOrDefault();
                //    var userid = SqlMapper.Query<int>(conn, @"select lastupdateuser from " + tablename + " where 1=1 and " + key + "=:pkvalue and rownum=1",
                //            new { pkvalue = pkvalue }).FirstOrDefault();
                //    if (count == 0)
                //        throw new Exception("依赖主键不存在");
                //    files.ForEach(f => {
                //        var i = SqlMapper.Query<int>(conn, @"select nvl(max(orders),0)+1 from res_attachmentlog where pkvalue=:pkvalue and tablename=:tablename",
                //            new { pkvalue = pkvalue, tablename = tablename }).FirstOrDefault();
                //        SqlMapper.ExecuteScalar<int>(conn, @"insert into res_attachmentlog
                //    (isvalid, lastupdateuser, creationtime, creationuser, lastupdatetime, mongoid, pkvalue, tablename, orders,type)
                //    values
                //    (1, :userid, sysdate, :userid, sysdate, :fileid, :pkvalue, :tablename, :orders,:type)",
                //        new { userid = userid, fileid = f.fileid, pkvalue = pkvalue, tablename = tablename, orders = i, type = f.type });
                //    });
                //}
            }
            catch (Exception)
            {
                throw new Exception("上传失败");
            }
            return files;
        }
        /// <summary>
        /// 附件表删除
        /// </summary>
        /// <param name="fileid"></param>
        /// <returns></returns>
        public static bool AttachmentDelete(string fileid)
        {
            try
            {
                //using (var conn = DBHelper.GetConnection())
                //{
                //    conn.ExecuteScalar<int>(@"update res_attachmentlog set isvalid = 0 where mongoid = :fileid
                //    ", new { fileid });
                //}
                return true;
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// 获取文件列表
        /// </summary>
        /// <param name="pkvalue"></param>
        /// <param name="tablename"></param>
        /// <returns></returns>
        public static List<files> GetFiles(string pkvalue, string tablename)
        {
            if (pkvalue == null || tablename == null)
            {
                throw new Exception("pkvalue或tablename为空");
            }
            var filelist = new List<files>();
            //using (var conn = DBHelper.GetConnection())
            //{
            //    
            //    filelist = conn.Query<files>(@"select t.mongoid filecodeid from res_attachmentlog t where t.tablename=:tablename and t.isvalid=1 and t.pkvalue=:pkvalue order by t.orders desc", new { pkvalue = pkvalue, tablename = tablename }).ToList();
            //    filelist.ForEach(f => { f.name = GetFileAutonym(f.filecodeid); f.type = GetFileType(f.filecodeid); f.kind = GetFileKind(f.filecodeid); });

            //    
            //}
            return filelist;
        }
        #endregion

        #region ==FTP文件存储==

        #endregion


        #region ==实体类==
        public class mognoinfo
        {
            public string pkvalue { get; set; }
            public string tablename { get; set; }
            public string fileid { get; set; }
            public string type { get; set; }
        }
        public class streamtype
        {
            public Stream stream { get; set; }
            public string type { get; set; }
        }
        public class files
        {
            public string filecodeid { get; set; }
            public string type { get; set; }
            public string name { get; set; }
            public string kind { get; set; }
        }
        #endregion
    }
}
